package template

import (
	gojson "encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"
)

var (
	templates = make(map[templateInterface]interface{})
	once      sync.Once
	typeInt64 = reflect.TypeOf(int64(0))
	typeString = reflect.TypeOf("")
	FilterReg *regexp.Regexp
)



type (
	BaseTemplate struct {
		DescriptionMap map[string]string
		NameMap map[string]string
		TypeMap map[string]string
		data map[string]interface{}
	}

	 templateInterface interface {
	 	NewInstance() interface{}
	 }
)



func Init() error {
	var err error
	once.Do(func() {
		//读取文件
		fileMap := make(map[string][]byte,0)
		var files []os.FileInfo
		dir := "./fairy/template/txt"
		files,err  =  ioutil.ReadDir(dir)
		if err != nil {
			return
		}

		suffix := ".json.txt"
		for _,file := range files {
			fileName := file.Name()
			if file.IsDir() || len(fileName) <= len(suffix) || fileName[len(fileName)-len(suffix):] != suffix {
				continue
			}

			var bytes []byte
			bytes,err = ioutil.ReadFile(fmt.Sprintf("%s/%s",dir,file.Name()))
			if err != nil {
				return
			}

			fileMap[fileName[0:len(fileName) - len(suffix)]] = bytes
		}

		for p,v := range templates {
			k := reflect.TypeOf(p)
			bytes,ok := fileMap[k.Elem().Name()]
			if !ok {
				continue
			}

			err = gojson.Unmarshal(bytes,&v)
			if err != nil {
				return
			}
			arr := v.([]interface{})
			if len(arr) < 3 {
				continue
			}

			descriptionMap := map[string]string{}
			for k,v := range arr[0].(map[string]interface{}) {
				descriptionMap[k] = v.(string)
			}

			nameMap := map[string]string{}
			for k,v := range arr[1].(map[string]interface{}) {
				nameMap[k] = v.(string)
			}

			typeMap := map[string]string{}
			for k,v := range arr[2].(map[string]interface{}) {
				typeMap[k] = v.(string)
			}



			baseTempate := &BaseTemplate{
				DescriptionMap: descriptionMap,
				NameMap: nameMap,
				TypeMap: typeMap,
			}
			//解析描述
			arr = arr[3:]
			mp := map[string]interface{}{}
			for _,item := range arr {
				m := item.(map[string]interface{})
				if err != nil {
					return
				}
				mp[m["id"].(string)] = m
			}

			baseTempate.data = mp
			err = setStructFieldByJsonName(p,baseTempate)
			if err != nil {
				return
			}
			templates[p] = baseTempate
		}
	})

	initFilterReg()
	return err
}

func GetTemplates(key templateInterface) []templateInterface {
	v,ok := templates[key]
	if !ok {
		return nil
	}

	arr := make([]templateInterface,0)
	mp := v.(*BaseTemplate).data
	for k,t := range  mp {
		if k == "0" {
			continue
		}

		arr = append(arr,t.(templateInterface))
	}

	return arr
}

func GetTemplateById(key templateInterface,id string) templateInterface {
	var o bool
	var v interface{}
	if b,ok := templates[key];ok {
		d := b.(*BaseTemplate).data
		if d == nil {
			return nil
		}

		if v,o = d[id];o {
			return v.(templateInterface)
		}
	}

	return nil
}

//将结构体里的成员按照json名字来赋值
func setStructFieldByJsonName(key templateInterface,baseTemplate *BaseTemplate) error {
	fields := baseTemplate.data

	tempMap := make(map[int]string,0)
	for k,value := range fields {
		temp := value.(map[string]interface{})

		item := key.NewInstance()
		v := reflect.ValueOf(item)
		for i := 0; i < v.Elem().NumField(); i++ {
			fieldInfo := v.Elem().Type().Field(i)
			name,ok := tempMap[i]
			if !ok {
				name = strings.ToLower(fieldInfo.Name[0:1]) + string([]rune(fieldInfo.Name)[1:])
				name = strings.Split(name, ",")[0]
				tempMap[i] = name
			}

			if value, ok := temp[name]; ok {
				switch fieldInfo.Type {
				case typeString:
					temp := ""
					if value != nil {
						temp = value.(string)
					}
					v.Elem().FieldByName(fieldInfo.Name).Set(reflect.ValueOf(temp))
				case typeInt64:
					temp,err := strconv.ParseInt(value.(string),10,64)
					if err != nil {
						return err
					}
					v.Elem().FieldByName(fieldInfo.Name).Set(reflect.ValueOf(temp))
				default:
				}
			}
		}
		fields[k] = item
	}


	return nil
}

func initFilterReg()  {
	list := GetTemplates(StrFilterKey)
	if list == nil {
		return
	}

	slice := StrFilterSlice{}
	for _,v := range list {
		slice = append(slice,v.(*StrFilter))
	}

	sort.Sort(&slice)

	strs := make([]string,0)
	for _,v := range slice {
		strs = append(strs,v.Description)
	}

	str := strings.Join(strs,"|")
	FilterReg = regexp.MustCompile(str)
}



